﻿$import( "SmitearWebGL.Renderer.Renderer" );
$import( "SmitearWebGL.Resources.FrameBufferObject" );
$import( "SmitearWebGL.Core.Render.RenderQueue" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.Diffuse" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.Specular" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.PostProcessing" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.SSAO" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.Blur" );
$import( "SmitearWebGL.Objects.Canvas.LightPrePass.Shadow" );

SmitearWebGL.Renderer.LPPRenderer = SmitearWebGL.Renderer.Renderer.extend(
{
	/******** constructor ********/

	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Renderer.LPPRenderer" );
	}
	,
	
	/******** public method ********/
	
	render : function( scene )
	{
		if ( ! scene ) return SmitearWebGL.Core.HResult.UNKNOWN_SCENE;
		
		var hr = SmitearWebGL.Core.HResult.SUCCESS;
		
		this._geomFBO.bind();
		
		var renderableObjects = scene._quadTree.getSearchResults();
		
		if ( renderableObjects.length == 0 )
		{
			this._geomFBO.unbind();
			SmitearWebGL.Objects.Viewport.setClearColor( this.context.gl, SmitearWebGL.Renderer.LPPRenderer.RTFClearColor );
			SmitearWebGL.Objects.Viewport.clear( this.context.gl, SmitearWebGL.Objects.Viewport.ClearBit.colorBufferBit | SmitearWebGL.Objects.Viewport.ClearBit.depthBufferBit );
			
			return SmitearWebGL.Core.HResult.SUCCESS;
		}
		
		var lights = scene._lights;
		var i, object;
		var renderSession = scene.getRenderSession();
		
		////////////////////////////////////////////// geom stage //////////////////////////////////////////////
		
		//depth pass
		this._renderQueue.reset();
		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX );
		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
		for ( i = 0; i < renderableObjects.length; ++ i )
		{
			object = renderableObjects[i];
			object.setProgram( this.context.programManager.getResourceByName( SmitearWebGL.Programs.InternalPrograms.Type.DEPTH ) );
			object.buildRenderEntry( this._renderQueue );
		}
		hr |= this._renderQueue.execute();
		
		//normal pass
		this._renderQueue.reset();
		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX );
		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
		for ( i = 0; i < renderableObjects.length; ++ i )
		{
			object = renderableObjects[i];
			object.setProgram( this.context.programManager.getResourceByName( SmitearWebGL.Programs.InternalPrograms.Type.NORMAL ) );
			object.buildRenderEntry( this._renderQueue );
		}
		hr |= this._renderQueue.execute();
		
		////////////////////////////////////////////// lighting stage //////////////////////////////////////////////
		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DIFFUSE_TEX );
		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
		
		hr |= this._diffuseCanvas.renderCallBack( renderSession, lights );
		
		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SPECULAR_TEX );
		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
		
		hr |= this._specularCanvas.renderCallBack( renderSession, lights );
		
		////////////////////////////////////////////// ssao sage //////////////////////////////////////////////
		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_TEX );
		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTSClearColor );
		
		hr |= this._ssaoCanvas.renderCallBack( renderSession );
		
//		//横向模糊
//		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_HBLUR_TEX );
//		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
//		
//		hr |= this._hBlurCanvas.renderCallBack();
//		
//		//纵向模糊
//		this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_VBLUR_TEX );
//		this._geomFBO.clearRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTTClearColor );
//		
//		hr |= this._vBlurCanvas.renderCallBack();
		
		////////////////////////////////////////////// maerial stage //////////////////////////////////////////////
		if ( SmitearWebGL.Scene._hdrEnable || SmitearWebGL.Renderer.LPPRenderer._Debug )
			this._geomFBO.useRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_MATERIAL_TEX );
		else
			this._geomFBO.unbind();
		
		SmitearWebGL.Objects.Viewport.setClearColor( this.context.gl, SmitearWebGL.Renderer.LPPRenderer.RTFClearColor );
		SmitearWebGL.Objects.Viewport.clear( this.context.gl, SmitearWebGL.Objects.Viewport.ClearBit.colorBufferBit | SmitearWebGL.Objects.Viewport.ClearBit.depthBufferBit );

		var diffMap = this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DIFFUSE_TEX );
		var specMap = this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SPECULAR_TEX );
		var aoMap = this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_TEX );
		
		this._renderQueue.reset();
		for ( i = 0; i < renderableObjects.length; ++ i )
		{
			object = renderableObjects[i];
			object.extra.diffMap = diffMap;
			object.extra.specMap = specMap;
			object.extra.aoMap = aoMap;
			object.setProgram( null );
			object.buildRenderEntry( this._renderQueue );
		}
		hr |= this._renderQueue.execute();
		
		////////////////////////////////////////////// shadow stage //////////////////////////////////////////////
		if ( SmitearWebGL.Scene._shadowEnable )
		{
			this.context.gl.enable( this.context.gl.STENCIL_TEST );
			this.context.gl.enable( this.context.gl.BLEND );
			this.context.gl.depthMask( false );
			this.context.gl.blendEquation( this.context.gl.FUNC_ADD );
			this.context.gl.blendFunc( this.context.gl.SRC_ALPHA, this.context.gl.ONE_MINUS_SRC_ALPHA );
			
			var program = this.context.programManager.getResourceByName( SmitearWebGL.Programs.InternalPrograms.Type.SHADOW_VOLUME );
			for ( i = 0; i < lights.length; ++ i )
			{
				hr |= program.activeShader();
		
				lights[i].glUniform( SmitearWebGL.ShaderUniform.lightColor, program.getShader() );
				lights[i].glUniform( SmitearWebGL.ShaderUniform.lightPosition, program.getShader() );
				
				SmitearWebGL.Objects.Viewport.clear( this.context.gl, SmitearWebGL.Objects.Viewport.ClearBit.stencilBufferBit );
				
				if ( ! SmitearWebGL.Scene._showShadowVolume )
				{
					this.context.gl.colorMask( false, false, false, false );
				}
				this.context.gl.enable( this.context.gl.POLYGON_OFFSET_FILL );
				this.context.gl.polygonOffset( 0.1, 1.0 );
				
				this.context.gl.enable( this.context.gl.CULL_FACE );
				this.context.gl.stencilFunc( this.context.gl.ALWAYS, 1, 0xFF );
				this.context.gl.stencilOpSeparate( this.context.gl.BACK, this.context.gl.KEEP, this.context.gl.INCR, this.context.gl.KEEP );
				this.context.gl.stencilOpSeparate( this.context.gl.FRONT, this.context.gl.KEEP, this.context.gl.DECR, this.context.gl.KEEP );
				
				for ( j = 0; j < renderableObjects.length; ++ j )
				{
					object = renderableObjects[j].getShadowMesh();
					
					if ( object )
					{
						//渲染反面
						this.context.gl.cullFace( this.context.gl.FRONT );
						hr |= object.renderCallBack();
				
						//渲染正面
						this.context.gl.cullFace( this.context.gl.BACK );
						hr |= object.renderCallBack();
					}
				}
				
				//渲染阴影
				this.context.gl.colorMask( true, true, true, true );
				this.context.gl.disable( this.context.gl.POLYGON_OFFSET_FILL );
				this.context.gl.stencilFunc( this.context.gl.NOTEQUAL, 0, 0xFF );
				this.context.gl.stencilOp( this.context.gl.KEEP, this.context.gl.KEEP, this.context.gl.KEEP );
				
				hr |= this._shadowCanvas.renderCallBack();
			}
			
			this.context.gl.depthMask( true );
			this.context.gl.disable( this.context.gl.BLEND );
			this.context.gl.disable( this.context.gl.STENCIL_TEST );
		}
		
		this._geomFBO.unbind();
		
		////////////////////////////////////////////// final stage //////////////////////////////////////////////
		if ( SmitearWebGL.Renderer.LPPRenderer._Debug )
		{
			SmitearWebGL.Objects.Viewport.setClearColor( this.context.gl, SmitearWebGL.Renderer.LPPRenderer.RTFClearColor );
			SmitearWebGL.Objects.Viewport.clear( this.context.gl );
			
			hr |= this._ppCanvas.renderCallBack();
		}
			
		return hr;
	}
	,
	
	/******** private method ********/
	
	_initFBO : function()
	{
		var sampler0 = this.context.resourceManager.getResourceByName( SmitearWebGL.Resources.InternalSamplers.Type.sampler0 );
		var informat = SmitearWebGL.Resources.Texture.Format.ARGB8;
		var format = SmitearWebGL.Resources.Texture.Format.ARGB8;
		var ubyte = SmitearWebGL.Resources.Texture.Type.UBYTE;
		var float32 = SmitearWebGL.Resources.Texture.Type.UBYTE;
		
		if ( this.context.capacity.supported.OES_texture_float )
			float32 = SmitearWebGL.Resources.Texture.Type.FLOAT32;
			
		var fboWidth = SmitearWebGL.Core.Math.ceilingPowerOfTwo( this.context.viewWidth );
		var fboHeight = SmitearWebGL.Core.Math.ceilingPowerOfTwo( this.context.viewHeight );
		
		this._geomFBO = this.context.resourceManager.createResource( "__light_pre_pass_fbo__", SmitearWebGL.Resources.FrameBufferObject );
		this._geomFBO.bind();
		this._geomFBO.createRenderSurface( fboWidth, fboHeight );
		
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX,
										informat, format, ubyte, sampler0 );
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX,
										informat, format, ubyte, sampler0 );
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DIFFUSE_TEX,
										informat, format, ubyte, sampler0 );
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SPECULAR_TEX,
										informat, format, ubyte, sampler0 );
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_MATERIAL_TEX,
										informat, format, float32, sampler0 );
		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_TEX,
										informat, format, ubyte, sampler0 );
//		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_HBLUR_TEX,
//										informat, format, ubyte, sampler0 );
//		this._geomFBO.createRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_VBLUR_TEX,
//										informat, format, ubyte, sampler0 );
		this._geomFBO.addRef();
		this._geomFBO.unbind();
	}
	,
	_initAllCanvas : function()
	{
		var material;
		var layer, layer1;
		
		this._diffuseCanvas = this.context.objectManager.createResource( "__light_processing_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.Diffuse );
		this._diffuseCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX ) );
		this._diffuseCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX ) );
		
		this._specularCanvas = this.context.objectManager.createResource( "__light_processing_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.Specular );
		this._specularCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX ) );
		this._specularCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX ) );
		
		//init ssao canvas
		this._ssaoCanvas = this.context.objectManager.createResource( "__ssao_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.SSAO );
		this._ssaoCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX ) );
		this._ssaoCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX ) );

		//init h_blur canvas
		this._hBlurCanvas = this.context.objectManager.createResource( "__ssao_h_blur_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.HBlur );
		this._hBlurCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_TEX ) );
		this._hBlurCanvas.calculateOffsets();

		//init v_blur canvas
		this._vBlurCanvas = this.context.objectManager.createResource( "__ssao_v_blur_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.VBlur );
		this._vBlurCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_SSAO_HBLUR_TEX ) );
		this._vBlurCanvas.calculateOffsets();
		
		this._shadowCanvas = this.context.objectManager.createResource( "__shadow_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.Shadow );
		
		//debug only
		if ( SmitearWebGL.Renderer.LPPRenderer._Debug )
		{
			this._ppCanvas = this.context.objectManager.createResource( "__post_processing_canvas__", SmitearWebGL.Objects.Canvas.LightPrePass.PostProcessing );
			this._ppCanvas.addTexture( this._geomFBO.getRenderTarget( SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX ) );
		}
	}
	,
	_createResource : function( params )
	{
		this._super();
		
		this._renderQueue = new SmitearWebGL.Core.Render.RenderQueue();
		
		this._initFBO();
		this._initAllCanvas();
	}
	,
	_destroyResource : function()
	{
		this._super();
		
		if ( this._diffuseCanvas )
			this._diffuseCanvas.release();
			
		if ( this._ssaoCanvas )
			this._ssaoCanvas.release();
			
		if ( this._shadowCanvas )
			this._shadowCanvas.release();
			
		this._geomFBO.release();
		
		this._diffuseCanvas = null;
		this._ssaoCanvas = null;
		this._geomFBO = null;
		
		if ( SmitearWebGL.Renderer.LPPRenderer._Debug )
		{
			this._ppCanvas.release();
			this._ppCanvas = null;
		}
	}
}
);

SmitearWebGL.Renderer.LPPRenderer.RTTClearColor = [0.0, 0.0, 0.0, 0.0];
SmitearWebGL.Renderer.LPPRenderer.RTFClearColor = [0.0, 0.0, 0.0, 1.0];
SmitearWebGL.Renderer.LPPRenderer.RTSClearColor = [1.0, 1.0, 1.0, 1.0];

SmitearWebGL.Renderer.LPPRenderer.RTUsage = 
{
	FBO_DEPTH_TEX :			0,
	FBO_NORMAL_TEX :		1,
	FBO_DIFFUSE_TEX :		2,
	FBO_SPECULAR_TEX :		3,
	FBO_MATERIAL_TEX :		4,
	FBO_SSAO_TEX :			5,
	FBO_SSAO_HBLUR_TEX :	6,
	FBO_SSAO_VBLUR_TEX :	7,
	TOTAL : 				8
}

SmitearWebGL.Renderer.LPPRenderer._Debug = false;